iT邦幫忙

2022 iThome 鐵人賽

DAY 20
0
Mobile Development

Android app 效能優化系列 第 20

使用 Profiler 找出記憶體的異常使用

  • 分享至 

  • xImage
  •  

我們在 Memory leak 篇介紹了如何使用 Profiler 來找出 Memory leak。接著將繼續介紹使用 Profiler 來分析記憶體。Profiler 所統計的記憶體使用是指單獨 App 的記憶體使用,不包含系統資源或其他 App。

要開啟 Profiler ,請在工具列點選 View → Tool Windows → Profiler。開啟會看到如下畫面,Profiler 可以用來分析 CPU、Memory 及 ENERGY,點選藍色的記憶體區塊進入記憶體詳細資訊。

https://ithelp.ithome.com.tw/upload/images/20221005/20111896Py8SiNT5hB.png

進入到記憶體區塊,可以看到 Profiler 將記憶體分為更多的部分來顯示使用量。你可以使用滑鼠在不同的時間軸移動,即會顯示不同時間點的記憶體配置狀況。

https://ithelp.ithome.com.tw/upload/images/20221005/20111896vW5jakxr7u.png

MEMORY 的種類:

Java:Java 或 Kotlin 的程式碼所用的記憶體。
Native:C 或 C++ 的程式碼所用的記憶體。
Graphics:圖片緩衝區 Queue 在螢幕上顯示時所用的記憶體。
Stack:Native、Java 的 Stack 使用的記憶體,通常跟執行緒數量有關。
Code:資源檔,如dex程式碼、so 檔、字型的記憶體。
Others:其他分類。

圖表最上方的粉紅色長條區塊時間軸,以圓點來表示使用者與 UI 的互動。例如 Activity 進入 Stopped、Activity 進入 Resumed 或者畫面的點擊,皆會記錄在上方。

https://ithelp.ithome.com.tw/upload/images/20221005/20111896eIDrWZV7SE.png

查看記憶體使用

在之前的 Out of memory 篇,我們介紹了使用縮圖來載入圖片資料以減入記憶體的使用。這裡就用同樣的範例來測試一下載入一張未縮圖的情況,使用 Profile 能不能看出問題。

binding.loadImage.setOnClickListener {
	//未使用縮圖,直接將原圖載入至Imageview
    BitmapFactory.decodeResource(resources, R.mipmap.scenery)
}

將 App 執行後開啟 Profiler 後,進入到 Memory 區塊。
https://ithelp.ithome.com.tw/upload/images/20221005/20111896zr3L8yYaE6.png

選擇 Capture heap dump 後,點選 Record 就可以建立一份記憶體快照。

https://ithelp.ithome.com.tw/upload/images/20221005/20111896Q3YPMkaaJI.png

完成後即可看到如下圖。預設會依照 Retained Size 由大到小排序,所以你只需要看最前面幾筆是不是有異常的部分。下圖很明顯可以看出 Bitmap 是有問題的。

https://ithelp.ithome.com.tw/upload/images/20221005/20111896juwyDomvqH.png

我們再把載入圖片的範例,改為使用縮圖的方式。

binding.loadImage.setOnClickListener {
    val options = BitmapFactory.Options().apply {
        inJustDecodeBounds = true
    }
    //在圖片載入到記憶體前,先取得圖片的寬高
    BitmapFactory.decodeResource(resources, R.mipmap.scenery, options)
    val imageHeight: Int = options.outHeight
    val imageWidth: Int = options.outWidth
    val imageType: String = options.outMimeType
    //在ImageView呈現的寬
    val smallImageWidth = 200
    //在ImageView呈現的高
    val smallImageHeight = 200
    //記算Size,縮小幾倍
    options.inSampleSize = calculateInSampleSize(options, smallImageWidth, smallImageHeight)
    options.inJustDecodeBounds = false
    binding.imageView.setImageBitmap(
        BitmapFactory.decodeResource(resources, R.mipmap.scenery, options)
        BitmapFactory.decodeResource(resources, R.mipmap.scenery)
    )
}

再次執行 Profiler → Capture heap dump。可以看到沒有特別高的記憶體使用了。
https://ithelp.ithome.com.tw/upload/images/20221005/20111896yVXaDYEAV1.png

最後,記憶體效能篇就到這篇告一個段落。在效能優化的處理,記憶體管理是非常重要的一環。記憶體在行動裝置上是非常寶貴的資源,應該儘可能的減少浪費。例如資源無法被釋放可能造成 Memory leak,不當的使用記憶體可能造成 Out of memory。另外搭配使用工具 Profiler、LeakCanary 檢測記憶體可以有效的找出效能問題。

參考:
https://developer.android.com/studio/profile/memory-profiler


上一篇
使用 LeakCanary 找出 Memory leak
下一篇
網路請求的效能優化
系列文
Android app 效能優化30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言